
#import "CABLeService.h"
#import "CABleDiscovery.h"
#import "CAPacket.h"
#import "CADeviceInfo.h"
#import "CAsDKTool.h"

#define BLES_WEAK_SELF  __weak typeof(self) weakSelf = self;
#define BLES_STRONG_SELF  __strong typeof(weakSelf) strongSelf = weakSelf; \
                     if (!strongSelf) return; \


NSString * const CABluetoothManagerReceiveDevices         = @"CABluetoothManagerReceiveDevices";
NSString * const CABluetoothManagerConnectingToDevice     = @"CABluetoothManagerConnectingToDevice";
NSString * const CABluetoothManagerConnectedToDevice      = @"CABluetoothManagerConnectedToDevice";
NSString * const CABluetoothManagerDisconnectedFromDevice = @"CABluetoothManagerDisconnectedFromDevice";
NSString * const CABluetoothManagerConnectionFailed       = @"CABluetoothManagerConnectionFailed";

NSString * const CAGenericServiceManagerDidReceiveValue         = @"CAGenericServiceManagerDidReceiveValue";
NSString * const CAGenericServiceManagerDidSendValue            = @"CAGenericServiceManagerDidSendValue";
NSString * const CAGenericServiceManagerReadError               = @"CAGenericServiceManagerReadError";
NSString * const CAGenericServiceManagerWriteError              = @"CAGenericServiceManagerWriteError";



NSString * const CASERVICE_UUID_DATA = @"00001822-0000-1000-8000-00805f9b34fb";
/*SR01 */

//NSString * const serviceUUIDString  = @"000066ff-0000-1000-8000-00805f9b34fb"; // 健康设备扫描UUID
NSString * const CAreadWriteCharacteristicUUIDString = @"000066fe-0000-1000-8000-00805f9b34fb"; // 读写数据
//NSString * const accCharacteristicUUIDString = @"000066ff-0000-1000-8000-00805f9b34fb"; // 计步

/*** OTA 相关 ***/
static CBUUID* SPOTA_SERVICE_CBUUID;
static CBUUID* SPOTA_MEM_DEV_CBUUID;
static CBUUID* SPOTA_GPIO_MAP_CBUUID;
static CBUUID* SPOTA_MEM_INFO_CBUUID;
static CBUUID* SPOTA_PATCH_LEN_CBUUID;
static CBUUID* SPOTA_PATCH_DATA_CBUUID;
static CBUUID* SPOTA_SERV_STATUS_CBUUID;
static CBUUID* SUOTA_VERSION_CBUUID;
static CBUUID* SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID;
static CBUUID* SUOTA_MTU_CBUUID;
static CBUUID* SUOTA_L2CAP_PSM_CBUUID;
/*** OTA 相关 ***/

/*SR01 */





@interface CABLeService() <CBPeripheralDelegate> {
@private
    CBPeripheral		*_servicePeripheral;
    
    CBUUID * _serviceUUIDMain;  // 主服务
    CBService *_serviceReadWrite;
    
    CBUUID * _uuidCharReadWrite;
    CBCharacteristic *_characteristicReadWrite; // 读写特征



    __weak id<StLeKeyFobProtocol>	_peripheralDelegate;
    __weak id<StLeKeyOTAProtocol>  _otaDelegate;  //ota 回调
}




@end



/// <#Description#>
@implementation CABLeService


@synthesize peripheral = _servicePeripheral, isManualDisconnect = _isManualDisconnect,
isExceptional = _isExceptional, isAlerting = _isAlerting;


#pragma mark -
#pragma mark Init
/****************************************************************************/
/*								Init										*/
/****************************************************************************/
- (id) initWithPeripheral:(CBPeripheral *)peripheral controller:(id<StLeKeyFobProtocol>)delegate
{
    self = [super init];
    if (self) {
        _servicePeripheral = peripheral;
        // 设置mtu
        
        [_servicePeripheral setDelegate:self];
        _peripheralDelegate = delegate;
        self.packetObj.dataDelegate = delegate;
        
        _serviceUUIDMain = [CBUUID UUIDWithString:CASERVICE_UUID_DATA];
        _uuidCharReadWrite = [CBUUID UUIDWithString:CAreadWriteCharacteristicUUIDString];
        
        
        self.isExceptional = NO;
        self.isAlerting = NO;
        self.isManualDisconnect = NO;
        self.reconnectCounts = 0;
        [self initOTAUUid];
        
        
    }
    return self;
}
- (instancetype) initWithPeripheral:(CBPeripheral *)peripheral
{
    self = [super init];
    if (self) {
        _servicePeripheral = peripheral;
        [_servicePeripheral setDelegate:self];
//        _peripheralDelegate = delegate;
//        self.packetObj.dataDelegate = delegate;
        
        _serviceUUIDMain = [CBUUID UUIDWithString:CASERVICE_UUID_DATA];
        _uuidCharReadWrite = [CBUUID UUIDWithString:CAreadWriteCharacteristicUUIDString];
        
        
        self.isExceptional = NO;
        self.isAlerting = NO;
        self.isManualDisconnect = NO;
        self.reconnectCounts = 0;
        [self initOTAUUid];
        
        
    }
    return self;
    
}

/// 初始化ota相关uuid
-(void)initOTAUUid {
    SPOTA_SERVICE_CBUUID = [CABleDiscovery sigUUIDToCBUUID:SPOTA_SERVICE_UUID];
    SPOTA_MEM_DEV_CBUUID = [CBUUID UUIDWithString:SPOTA_MEM_DEV_UUID];
    SPOTA_GPIO_MAP_CBUUID = [CBUUID UUIDWithString:SPOTA_GPIO_MAP_UUID];
    SPOTA_MEM_INFO_CBUUID = [CBUUID UUIDWithString:SPOTA_MEM_INFO_UUID];
    SPOTA_PATCH_LEN_CBUUID = [CBUUID UUIDWithString:SPOTA_PATCH_LEN_UUID];
    SPOTA_PATCH_DATA_CBUUID = [CBUUID UUIDWithString:SPOTA_PATCH_DATA_UUID];
    SPOTA_SERV_STATUS_CBUUID = [CBUUID UUIDWithString:SPOTA_SERV_STATUS_UUID];
    SUOTA_VERSION_CBUUID = [CBUUID UUIDWithString:SUOTA_VERSION_UUID];
    SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID = [CBUUID UUIDWithString:SUOTA_PATCH_DATA_CHAR_SIZE_UUID];
    SUOTA_MTU_CBUUID = [CBUUID UUIDWithString:SUOTA_MTU_UUID];
    SUOTA_L2CAP_PSM_CBUUID = [CBUUID UUIDWithString:SUOTA_L2CAP_PSM_UUID];
    
    _suotaVersion = 0;
    _suotaMtu = DEFAULT_MTU;
    _suotaPatchDataSize = DEFAULT_FILE_CHUNK_SIZE;
    _suotaL2CapPsm = 0;
}

-(void)setAdvData:(NSDictionary *)advertisementData
{
    NSData * manufacturerData = advertisementData[@"kCBAdvDataManufacturerData"];
    Byte * manufacturerBybtes =  (Byte *)(manufacturerData.bytes);
    NSString *advertisementName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];

    if(manufacturerData.length < 2) {
        return;
    }
    
    NSArray<NSArray<NSNumber *> * > *cidArray = [self.class cidArray];
    //@[
//        @[@(0XA5), @(0X0D) ], // 日本
//        @[@(0XAD), @(0X0D) ],  // sr23心电
//        @[@(0X7B), @(0X0E) ],// 法国Circular
//    ]; // 默认值,也可外部赋值
    
    BOOL newAnaly = NO;
    for (NSArray<NSNumber *> * cid in cidArray) {
        if (manufacturerBybtes[0] == [cid[0] unsignedCharValue]
            && manufacturerBybtes[1] == [cid[1] unsignedCharValue])
        {
            newAnaly = YES;
            break;
        }
    }
    
    if (newAnaly) {
        // 日本戒指 广播包不同
        NSString *macString = [NSString  stringWithFormat:@"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", manufacturerBybtes[2], manufacturerBybtes[3], manufacturerBybtes[4], manufacturerBybtes[5], manufacturerBybtes[6], manufacturerBybtes[7]];
        self.macAddress = macString;
        
        self.deviceColor = (NSUInteger)(manufacturerBybtes[8] & 0XFF); // 颜色
        self.deviceSize = manufacturerBybtes[9] & 0xFF; // 尺寸
        
        uint8_t isCharging = (manufacturerBybtes[10] >> 7) & 0X01; // 充电状态
        uint8_t batteryLevel = manufacturerBybtes[10] & 0X7F;  // 电量
        
        NSInteger chipType = (manufacturerBybtes[11] >> 4) & 0XFF; // 主芯片型号
        NSUInteger deviceGeneration = (manufacturerBybtes[11]) & 0X0F; // 迭代版本
        self.mainChipType = chipType;
        self.deviceGeneration = deviceGeneration;
        self.scanIsCharge = @(isCharging);
        self.scanBatteryLevel = @(batteryLevel);
        self.advDataLocalName = advertisementName;
        
        // sn
        NSString *snString = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", manufacturerBybtes[12],
                              manufacturerBybtes[13],
                              manufacturerBybtes[14],
                              manufacturerBybtes[15],
                              manufacturerBybtes[16],
                              manufacturerBybtes[17]];
        long long snNUmber = [snString longLongValue];
        snString = [NSString stringWithFormat:@"%lld", snNUmber];
        self.snString = snString;
        
        if (manufacturerData.length >= 19) {
            self.projectId = manufacturerBybtes[18];
        }
        
    }  else {
        self.macAddress = [CAsDKTool macAddressFromBleAvdData:advertisementData];
        self.advDataLocalName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
        if (manufacturerData.length >= 6) {
            // 解析颜色和尺寸
            Byte *byte = (Byte *)[manufacturerData bytes];
            self.deviceColor = (NSUInteger)(byte[4]); // color: 0-black,1-silver, 2-gold, 3-rose gold
        
            self.deviceSize = byte[5] & 0xFF; // ring's size
        }
        if (manufacturerData.length >= 8)
        {

            Byte *byte = (Byte *)[manufacturerData bytes];
            
            uint8_t b6 = byte[6];
            BOOL isCharging = (b6 >> 7) & 0X01; // is charging
            uint8_t batteryLevel = b6 & 0X7F;  // battery level,range in 0-100
            
            
            uint8_t b7 = byte[7];
            NSInteger chipType = (byte[7] >> 4) & 0XFF; // main chip
            NSUInteger deviceGeneration = (byte[7]) & 0X0F; // generation
            self.mainChipType = chipType;
            self.deviceGeneration = deviceGeneration;
        }
        
        
    //    if ([advertisementName containsString:@"SR23_"]) {
    //        self.isSupportEcg = YES;
    //    }
        
        if ([advertisementName containsString:@"w"] || [advertisementName containsString:@"W"]) {
            // 无线充电版本
            self.isWirenessCharge = @YES; // 标记为无线充电
        }
    }

}

+(NSArray<NSArray<NSNumber *> * > *)cidArray
{
    NSArray<NSArray<NSNumber *> * > *cidArray = @[
        @[@(0XA5), @(0X0D) ], // 日本
        @[@(0XAD), @(0X0D) ],  // sr23心电
        @[@(0X7B), @(0X0E) ],// 法国Circular
    ]; // 默认值,也可外部赋值
    return cidArray;
}

-(void)setPerpheralDelegate:(id<StLeKeyFobProtocol>)delegate {
    _peripheralDelegate = delegate;
    self.packetObj.dataDelegate = delegate;
}
-(id<StLeKeyFobProtocol>)perpheralDelegate
{
    return _peripheralDelegate;
}
-(void)setOtaDelegate:(id<StLeKeyOTAProtocol>)otaDelegate {
    _otaDelegate = otaDelegate;
}

- (void) dealloc {
    if (_servicePeripheral) {
//        [_servicePeripheral setDelegate:nil]; //close by lzp 20201216
        _servicePeripheral = nil;
        
    }
}


- (void) reset
{
    [self stopRssiTimer];
    if (_servicePeripheral) {
        _servicePeripheral = nil;
    }
}

-(BOOL)isConnected
{
    return self.peripheral.state == CBPeripheralStateConnected;
}


#pragma mark -
#pragma mark Service interaction
/****************************************************************************/
/*							Service Interactions							*/
/****************************************************************************/
- (void) start
{
//    setDeviceAlertService = nil;
//    setMobileAlertService = nil;
//    batteryService = nil;
//    measureService = nil;
//    versionService = nil;
    
    _serviceReadWrite = nil;
    _characteristicReadWrite = nil;
    
    NSArray	*serviceArray	= @[_serviceUUIDMain, SPOTA_SERVICE_CBUUID];
//    DebugNSLog(@"_serviceUuidBattery uuid = %@", _serviceUuidBattery.UUIDString);
    [_servicePeripheral discoverServices:serviceArray];
//    if (_servicePeripheral.delegate == nil) {
    [_servicePeripheral setDelegate:self];
//    }
    DebugNSLog(@"_servicePeripheral.delegate = %@ self = %@", _servicePeripheral.delegate, self);
    //2s read rssi
    //    rssiTimer = [NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:@selector(rssiTimerProc:) userInfo:nil repeats:YES];
    
    
    self.isExceptional = NO;
    self.isAlerting = NO;
    self.isManualDisconnect = NO;
    self.reconnectCounts = 0;
}


- (void)rssiTimerProc:(NSTimer *)timer
{
    [_servicePeripheral readRSSI];
}

- (void)stopRssiTimer
{
//    if ([rssiTimer isValid]) {
//        [rssiTimer invalidate];
//    }
}



-(void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error
{
    if (error == nil) {
        [_peripheralDelegate stkeyFobServiceDidReadRSSI:self];
    } else {
        DebugNSLog(@"RSSI ERROR:%@", [error debugDescription]);
    }
}


/// 获取心率血氧开关
/// @param isStart isStart = NO 关闭  isStart = yes 开启
-(void)deviceOxygenAndHrvBoth:(BOOL)both IsOpen:(BOOL)isStart {
    if (!_characteristicReadWrite) {
        return;
    }
    NSData *cmdData = [CAPacket packGetOxygenHrvBoth:both IsOpen:isStart];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

-(void)cmdDeviceShutDown {

    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    NSData *cmdData = [CAPacket packShutDown];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}


-(void)cmdDeviceReboot {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packReboot];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];

}

-(void)cmdDeviceBattery {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packBattery];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

-(void)cmdGetSteps
{
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf->_characteristicReadWrite == nil) {
            DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
            return;
        }
        BLES_WEAK_SELF
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            BLES_STRONG_SELF
        NSData *cmdData = [CAPacket packGetSteps];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
        });
    });
}

-(void)cmdGetTemperature
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    BLES_WEAK_SELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BLES_STRONG_SELF
        NSData *cmdData = [CAPacket packGetTemperature];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdFactoryReset
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    BLES_WEAK_SELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BLES_STRONG_SELF
    NSData *cmdData = [CAPacket PackReset];
    [strongSelf-> _servicePeripheral writeValue:cmdData forCharacteristic:strongSelf-> _characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdGetDevInfoFive {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        
        NSData *cmdData = [CAPacket PackGetDevInfoFive]; // 设备信息5
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdSetMeasureDuration:(NSInteger)durations 
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSData *cmdData = [CAPacket PackSetHrMeasureDuration:durations]; // 测量时长
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdECGMeasure:(BOOL)on SampleRate:(uint16_t)sampleRate InnerClockSource:(uint8_t)clockSource EcgPgaGain:(uint8_t)ecgPgaGain DispSrc:(BOOL)isFilterWave {
    if (_characteristicReadWrite == nil)
    {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSData *cmdData = [CAPacket PackEcgMeasure:on SampleRate:sampleRate InnerClockSource:clockSource EcgPgaGain:ecgPgaGain DispSrc:isFilterWave];
        
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdEcgAndPpgMeasure:(BOOL)on {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSData *cmdData = [CAPacket PackEcgAndPpgMeasure:on]; // 测量时长
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdSetStepCountingThreshold:(uint8_t)threshold 
{
    
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    
    if (threshold > 0x3F) {
        DebugNSLog(@"threshold must be in range 0 - 0x3F !!");
        return;
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        NSData *cmdData = [CAPacket PackSetStepCountingThreshold:threshold]; // 测量时长
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdSn {
    // 获取sn
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    BLES_WEAK_SELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BLES_STRONG_SELF
        NSData *cmdData = [CAPacket packSN];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdDevInfo {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback");
        return;
    }
    
    BLES_WEAK_SELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BLES_STRONG_SELF
        NSData *cmdData = [CAPacket packDevInfo];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}

-(void)cmdTimeSync:(NSDate *)date
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    BLES_WEAK_SELF
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        BLES_STRONG_SELF
        NSData *cmdData = [CAPacket packTimeSync:date];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
        
    });
}

/// 血氧测量设置
/// @param startHor 开始 时
/// @param startMin 开始 时分
/// @param startSecond 开始 秒
/// @param endHor 结束 时
/// @param endMin 结束 分
/// @param endSec 结束 秒
/// @param interval 间隔 单位:分钟
-(BOOL)cmdSettingOxygenMeasure:(NSUInteger)startHor
                      StartMin:(NSUInteger)startMin
                      StartSec:(NSUInteger)startSecond
                        Endhor:(NSUInteger)endHor
                        EndMin:(NSUInteger)endMin
                        EndSec:(NSUInteger)endSec
                      Interval:(NSUInteger)interval IsOn:(BOOL)isOn {
    if (startHor > 23 || startMin > 59 || startSecond > 59) {
        return NO;
    }
    
    
    if (endHor > 23 || endMin > 59 || endSec > 59) {
        return NO;
    }
   
    if (endHor < startHor) {
        return NO;
    }
    
    if (interval > 59) {
        return NO;
    }
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }

    NSData *cmdData = [CAPacket packSettingOxygenMeasure:startHor StartMin:startMin StartSec:startSecond Endhor:endHor EndMin:endMin EndSec:endSec Interval:interval IsOn:isOn];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    
    return YES;
    
}

-(void)cmdSettingHeartRateMeasurInterval:(NSUInteger)hrInterval SkinTemperatureInterval:(NSUInteger)skinTemperatureInterval IsOn:(BOOL)isOn
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packSettingHeartRateMeasurInterval:hrInterval SkinTemperatureInterval:skinTemperatureInterval IsOn:isOn];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    
}

-(void)cmdSettingSportMode:(NSUInteger)startHor StartMin:(NSUInteger)startMin
                  StartSec:(NSUInteger)startSecond Endhor:(NSUInteger)endHor
                    EndMin:(NSUInteger)endMin EndSec:(NSUInteger)endSec
                HrIntreval:(NSUInteger)hrInterval SkinTemperatureInterval:(NSUInteger)skinTemperatureInterval
                  BloodOxygenInterval:(NSUInteger)oxygeninterval
                      IsOn:(BOOL)isOn
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packSportMode:startHor StartMin:startMin
                                     StartSec:startSecond Endhor:endHor
                                       EndMin:endMin EndSec:endSec
                                   HrIntreval:hrInterval SkinTemperatureInterval:skinTemperatureInterval
                                     BloodOxygenInterval:oxygeninterval
                                         IsOn:isOn];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    
}

// 获取历史个数
-(void)cmdHistoryCount {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packHistoryCount];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

-(void)cmdStartOemAuth {
    
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packStartAes];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

-(void)cmdOEMSendR2:(NSData *)r2 {
    
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packSendR2:r2];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

// 改广播名
-(BOOL)cmdModifyBRcastName:(NSString *)name HideMac:(BOOL)hideMac {
    
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    
    if (name.length == 0 || name.length > 16) {
        return NO;
    }
    
    NSData *cmdData = [CAPacket packModifyBRcastName:name HideMac:hideMac];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    
    return YES;
}


-(void)cmdBindeDevice:(BOOL)bind {
 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSData *cmdData = [CAPacket packBindDevice:bind];
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
        
    });
}


-(void)cmdOEMSwitch:(BOOL)on
{
 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSData *cmdData = [CAPacket packOEMSwitch:on];
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
        
    });
}

//-(void)cmdSOSSettingDoubleTapTimes:(uint8_t)doubleTapTimes
//    SingleTapInterval:(uint8_t)singleTapInterval TapDetectionThreshold:(uint8_t)tapDetectionThreshold
//           DoubleTapEffectStartTime:(uint8_t)doubleTapEffectStartTime DoubleTapEffectEndTime:(uint8_t)doubleTapEffectEndTime Open:(BOOL)sosOpen
//{
//    if (_characteristicReadWrite == nil) {
//        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
//        return;
//    }
//
//    NSData *cmdData = [SRPacket packSOSSettingDoubleTapTimes:doubleTapTimes
//                                           SingleTapInterval:singleTapInterval TapDetectionThreshold:tapDetectionThreshold
//                                                  DoubleTapEffectStartTime:doubleTapEffectStartTime DoubleTapEffectEndTime:doubleTapEffectEndTime Open:sosOpen];
//    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
//    
//}

-(void)cmdHistoryData {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    NSData *cmdData = [CAPacket packHistoryData];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

-(void)cmdClearHistory {
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSData *cmdData = [CAPacket packClearHistory];
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}


-(void)cmdLedMeasure:(BOOL)on LedColor:(uint8_t)ledColor AutoAdjBri:(BOOL)autoAdjBri Current:(uint8_t)current SampleRate:(uint8_t)sampleRate
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method srBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSData *cmdData = [CAPacket packLedMeasure:on LedColor:ledColor AutoAdjBri:autoAdjBri Current:current SampleRate:sampleRate];
        [self->_servicePeripheral writeValue:cmdData forCharacteristic:self->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
}
///
/// @param start 开关
/// @param valInterval 设备取值间隔 秒
/// @param durationMIn 设备持续时间 分钟
-(void)cmdSportMode:(BOOL)start ValueINterval:(uint16_t)valInterval Duration:(uint16_t)durationMIn WorkType:(CA_WORKOUT_TYPE)workoutType 
{
    
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return;
    }

    SDKSportType spType = 0;
    if (workoutType ==     CA_WORKOUT_TYPE_RUNNING) {
        spType = SDK_SP_RUNNING;
    }
    
    NSData *cmdData = [CAPacket packSoprtMode:start ValueINterval:valInterval Duration:durationMIn SportType:spType];
    [_servicePeripheral writeValue:cmdData forCharacteristic:_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
}

#pragma mark --CSEM
// 设置用户信息
//性别: 0 男性、1 女性
//年龄: 范围 1-115
//身高: 单位 mm，范围 1200-3000
//体重: 单位 kg，范围 30-200
-(BOOL)cmdSetUsrInfoToDev:(NSUInteger)gender Age:(NSUInteger)ageYear Height:(NSUInteger)height Weight:(NSUInteger)weight
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    
    if (height < 1200 || height > 3000) {
        return NO;
    }
    
    if(weight < 30 || weight > 200) {
        return NO;

    }
    if (ageYear < 1 || ageYear > 115) {
        return NO;
    }
    
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        
        
        NSData *cmdData = [CAPacket packSetUsrInfoToDev:gender Age:ageYear Height:height Weight:weight IsGet:NO];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    
    return YES;
}

-(BOOL)cmdGetUsrInfoToDev
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;

    NSData *cmdData = [CAPacket packSetUsrInfoToDev:0 Age:0 Height:0 Weight:0 IsGet:YES];
    
    [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

-(BOOL)cmdGetLastActivity
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packGetLastActivity];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

-(BOOL)cmdCleanActivityHistory
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packCleanActivityHis];
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

-(BOOL)cmdGetHistoryCntOfActvtyDtctnAndSwimAndSlepHist
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
    NSData *cmdData = [CAPacket packGetHisCntOfActivAndSwimAndSleep];
    
    [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

//-(BOOL)cmdGetHistoryDataOfActvtyDtctnAndSwimAndSlepHist
//{
//    if (_characteristicReadWrite == nil) {
//        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
//        return NO;
//    }
//    __weak typeof(self) weakSelf = self;
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
//        __strong typeof(weakSelf) strongSelf = weakSelf;
//        NSData *cmdData = [SRPacket packGetHisDataOfActivAndSwimAndSleep:0];
//        
//        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
//    });
//    return YES;
//}

-(BOOL)cmdGetHistoryDataOfActvtyDtctnAndSwimAndSlepHistMax:(uint32_t)maxUUid
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packGetHisDataOfActivAndSwimAndSleep:maxUUid];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}



-(BOOL)cmdSetCsemMea:(uint32_t)type IsSet:(BOOL)isSet DuraNoSleep:(uint32_t)meaDuraNoSleep IntervNosleep:(uint32_t)meaIntervNoSleep DuraInSleep:(uint32_t)meaduraInSleep IntervInsleep:(uint32_t)meaIntervInSleep
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packCmDura:isSet Type:type DuraNoSlp:meaDuraNoSleep IntervNoslp:meaIntervNoSleep DuraInSlp:meaduraInSleep IntervInslp:meaIntervInSleep];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
    
}

-(BOOL)cmdSetCSEMexercise:(uint8_t)subCmd ExerciseType:(uint8_t)execType PoolSize:(uint8_t)sizeType HeartrateStorageInterval:(uint16_t)hrStoreInterv DurationMins:(uint16_t)duraMins
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    
    if (hrStoreInterv < 10 && (subCmd == 1)) {
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packCMexercise:subCmd ExerciseType:execType PoolSize:sizeType HeartrateStorageInterval:hrStoreInterv DurationMins:duraMins];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

-(BOOL)cmdSetCSEMexerciseRealReportSwitch:(BOOL)on
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packexerciseRealReportSwitch:on];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}

-(BOOL)cmdDeviceAlgorithm:(BOOL)isSet Type:(uint8_t)algorithmType
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method caBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    
    if (algorithmType > 1) {
        
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
    NSData *cmdData = [CAPacket packDeviceAlgorithm:isSet Type:algorithmType];

    [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
    
}

-(BOOL)cmdGetLastActivity_2
{
    if (_characteristicReadWrite == nil) {
        DebugNSLog(@"Please call after the method srBleDeviceDidReadyForReadAndWrite callback, function:%s", __FUNCTION__);
        return NO;
    }
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSData *cmdData = [CAPacket packGetLastActivity_2];
        
        [strongSelf->_servicePeripheral writeValue:cmdData forCharacteristic:strongSelf->_characteristicReadWrite type:CBCharacteristicWriteWithResponse];
    });
    return YES;
}
/// 解析是否有ota相关数据
/// @param characteristic 特征
/// @param error 错误指针
-(void)otaUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (!error) {
        DebugNSLog(@"Value for %@ is %@", characteristic.UUID, characteristic.value);
        BOOL canSend = NO;
        // Check for SUOTA info
        if ([characteristic.UUID isEqual:CABLeService.SUOTA_VERSION_CBUUID]) {
            uint8_t value = 0;
            [characteristic.value getBytes:&value length:1];
            _suotaVersion = value;
            DebugNSLog(@"SUOTA version: %d", self.suotaVersion);  // 原软件 版本号
            
        } else if ([characteristic.UUID isEqual:CABLeService.SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID]) {
            uint8_t value[2] = { DEFAULT_FILE_CHUNK_SIZE, 0 };
            [characteristic.value getBytes:&value length:2];
            _suotaPatchDataSize = (value[1] << 8) | value[0];
            DebugNSLog(@"SUOTA patch data size: %d", self.suotaPatchDataSize);
            
        } else if ([characteristic.UUID isEqual:CABLeService.SUOTA_MTU_CBUUID]) {
            uint8_t value[2] = { DEFAULT_MTU, 0 };
            [characteristic.value getBytes:&value length:2];
            _suotaMtu = (value[1] << 8) | value[0];
            DebugNSLog(@"SUOTA MTU: %d", self.suotaMtu);
            
        } else if ([characteristic.UUID isEqual:CABLeService.SUOTA_L2CAP_PSM_CBUUID]) {
            uint8_t value[2] = { 0, 0 };
            [characteristic.value getBytes:&value length:2];
            _suotaL2CapPsm = (value[1] << 8) | value[0];
            DebugNSLog(@"SUOTA L2CAP PSM: %d", self.suotaL2CapPsm);
            
        }
        
        if ([characteristic.UUID isEqual:CABLeService.SPOTA_SERV_STATUS_CBUUID]) {
            canSend = YES;
        }
        
        if (canSend) {
            [[NSNotificationCenter defaultCenter] postNotificationName:CAGenericServiceManagerDidReceiveValue object:characteristic];
            
            if ([_otaDelegate respondsToSelector:@selector(srOtaDidReceiveValue:)]) {
                [_otaDelegate srOtaDidReceiveValue:characteristic];
            }
        }
        
    }
}

- (void) otaWriteValue:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID data:(NSData*)data
{
    [self otaWriteValue:serviceUUID characteristicUUID:characteristicUUID data:data type:CBCharacteristicWriteWithResponse];
}

- (void) otaWriteValueWithoutResponse:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID data:(NSData*)data
{
    [self otaWriteValue:serviceUUID characteristicUUID:characteristicUUID data:data type:CBCharacteristicWriteWithoutResponse];
}

- (void) otaWriteValue:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID data:(NSData*)data type:(CBCharacteristicWriteType)responseType
{
    CBService* service = [self findServiceWithUUID:serviceUUID];
    if (!service) {
        DebugNSLog(@"Could not find service with UUID %@", serviceUUID.UUIDString);
        return;
    }

    CBCharacteristic* characteristic = [self findCharacteristicWithUUID:characteristicUUID forService:service];
    if (!characteristic) {
        DebugNSLog(@"Could not find characteristic with UUID %@", characteristicUUID.UUIDString);
        return;
    }

    [self.peripheral writeValue:data forCharacteristic:characteristic type:responseType];
}

- (void) setNotifications:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID enable:(BOOL)enable
{
    CBService* service = [self findServiceWithUUID:serviceUUID];
    if (!service) {
        DebugNSLog(@"Could not find service with UUID %@", serviceUUID.UUIDString);
        return;
    }

    CBCharacteristic* characteristic = [self findCharacteristicWithUUID:characteristicUUID forService:service];
    if (!characteristic) {
        DebugNSLog(@"Could not find characteristic with UUID %@", characteristicUUID.UUIDString);
        return;
    }

    [self.peripheral setNotifyValue:enable forCharacteristic:characteristic];
}

- (CBCharacteristic*) findCharacteristicWithUUID:(CBUUID*)UUID forService:(CBService*)service {
    for (CBCharacteristic* characteristic in service.characteristics)
{
        if ([characteristic.UUID isEqual:UUID])
            return characteristic;
    }
    return nil;
}
- (CBService*) findServiceWithUUID:(CBUUID*)UUID
{
    for (CBService* service in self.peripheral.services) {
        if ([service.UUID isEqual:UUID])
            return service;
    }
    return nil;
}
- (void) readValue:(CBUUID*)serviceUUID characteristicUUID:(CBUUID*)characteristicUUID {
    CBService* service = [self findServiceWithUUID:serviceUUID];
    if (!service) {
        DebugNSLog(@"Could not find service with UUID %@", serviceUUID.UUIDString);
        return;
    }

    CBCharacteristic* characteristic = [self findCharacteristicWithUUID:characteristicUUID forService:service];
    if (!characteristic) {
        DebugNSLog(@"Could not find characteristic with UUID %@", characteristicUUID.UUIDString);
        return;
    }

    [self.peripheral readValueForCharacteristic:characteristic];
}
#pragma mark -
#pragma mark Characteristics interaction
/****************************************************************************/
/*						Characteristics Interactions						*/
/****************************************************************************/



#pragma mark -- CBPeripheralDelegate

/// 蓝牙外设服务确认
/// @param peripheral 蓝牙外设
/// @param error 错误
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    NSArray        *services    = nil;
    
    if (peripheral != _servicePeripheral) {
        DebugNSLog(@"Wrong Peripheral.\n");
        return ;
    }
    
    if (error != nil) {
        //        DebugNSLog(@"Error %@\n", error);
        return ;
    }
    
    services = [peripheral services];
    if (!services || ![services count]) {
        return ;
    }
    
    for (CBService *service in services) {
        DebugNSLog(@"foud service %@ ", service.UUID);
        if ([service.UUID isEqual:_serviceUUIDMain]) {
            _serviceReadWrite = service;
            [_servicePeripheral discoverCharacteristics:@[_uuidCharReadWrite,]
                                             forService:service];
        }
        
        if ([CABleDiscovery sigUUIDFromCBUUID:service.UUID] == SPOTA_SERVICE_UUID) {  // ota 主服务
            [_servicePeripheral discoverCharacteristics:nil
                                             forService:service];
        }
                
    }
   

}


- (void) peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error;
{
    
    if (error != nil) {
        //        DebugNSLog(@"Error %@\n", error);
        return ;
    }
    
    DebugNSLog(@"发现特征: %@", [service UUID].UUIDString);
    CBCharacteristic *characteristic;
    NSArray        *characteristics    = [service characteristics];
    if ([[service UUID] isEqual:_serviceUUIDMain]) { // 数据读取uuid

        for (characteristic in characteristics) {
            
            //_characteristicRecord
            
            if ([characteristic.UUID isEqual:_uuidCharReadWrite]) {
                _characteristicReadWrite = characteristic;
                [_servicePeripheral setNotifyValue:YES forCharacteristic:_characteristicReadWrite];

                if ([_peripheralDelegate respondsToSelector:@selector(stkeyFobServiceDidReadyForReadWrite:)]) {
                    [_peripheralDelegate stkeyFobServiceDidReadyForReadWrite:self];
                }
            }
        
        }/* for (characteristic in characteristics) */
//        return ;
    }
    
    // Read device info
    if ([CABleDiscovery sigUUIDFromCBUUID:service.UUID] == ORG_BLUETOOTH_SERVICE_DEVICE_INFORMATION) {
        for (CBCharacteristic *characteristic in service.characteristics) {
            DebugNSLog(@" -- Characteristic %@ (%@)", characteristic.UUID, characteristic);
            switch ([CABleDiscovery sigUUIDFromCBUUID:characteristic.UUID]) {
                case ORG_BLUETOOTH_CHARACTERISTIC_MANUFACTURER_NAME_STRING:
                case ORG_BLUETOOTH_CHARACTERISTIC_MODEL_NUMBER_STRING:
                case ORG_BLUETOOTH_CHARACTERISTIC_FIRMWARE_REVISION_STRING:
                case ORG_BLUETOOTH_CHARACTERISTIC_SOFTWARE_REVISION_STRING:
                    [self readValue:service.UUID characteristicUUID:characteristic.UUID];
                    break;
            }
        }
    }
    

    // Read SUOTA info
    if ([CABleDiscovery sigUUIDFromCBUUID:service.UUID] == SPOTA_SERVICE_UUID) {
        for (CBCharacteristic *characteristic in service.characteristics) {
            DebugNSLog(@"OTA -- Characteristic %@ (%@)", characteristic.UUID, characteristic);
            
            BOOL can = NO;
            if ([characteristic.UUID isEqual:CABLeService.SUOTA_VERSION_CBUUID]) {
                DebugNSLog(@"lzp found SUOTA_VERSION_CBUUID %@", CABLeService.SUOTA_VERSION_CBUUID);
                can = YES;
            }
            if ([characteristic.UUID isEqual:CABLeService.SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID]) {
                DebugNSLog(@"lzp found SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID %@", CABLeService.SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID);
                can = YES;
            }
            
            if ([characteristic.UUID isEqual:CABLeService.SUOTA_MTU_CBUUID]) {
                DebugNSLog(@"lzp found SUOTA_MTU_CBUUID %@", CABLeService.SUOTA_MTU_CBUUID);
                can = YES;
            }
            
            if ([characteristic.UUID isEqual:CABLeService.SUOTA_L2CAP_PSM_CBUUID]) {
                DebugNSLog(@"lzp found SUOTA_MTU_CBUUID %@", CABLeService.SUOTA_L2CAP_PSM_CBUUID);
                can = YES;
            }
            
            if ([[characteristic UUID] isEqual: SPOTA_SERV_STATUS_CBUUID]) {
                [self.peripheral setNotifyValue:YES forCharacteristic:characteristic];
            }
            
            if (can) {
                [self readValue:service.UUID characteristicUUID:characteristic.UUID];
            }
        }
    }
    
}


- (void) peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
//    DebugNSLog(@"did update value of char :%@", characteristic.UUID.UUIDString);
    
    if (peripheral != _servicePeripheral) {
        DebugNSLog(@"Wrong peripheral");
        return ;
    }
    
    if ([error code] != 0) {
        DebugNSLog(@"Characteristic Error %@\n", error);
        		return ;
    }
    
    if ([characteristic.UUID isEqual:_characteristicReadWrite.UUID]) {
        // 读取到数据
//        if ([self.recordDealDelegate respondsToSelector:@selector(receiveRecordData:)]) {
//            [self.recordDealDelegate receiveRecordData:[characteristic value]];
//        }
        // 兼容sr23 收包大于20字节问题
        NSData *totalData = [characteristic value];
//        DebugNSLog(@"内部收到长度 %lu", (unsigned long)totalData.length);

        for (int i = 0; i < (totalData.length/20); i++) {
            NSData *subData = [totalData subdataWithRange:NSMakeRange(i * 20, 20)];
            [self.packetObj receiveData:subData];
//            DebugNSLog(@"内部收到 %@", subData);
        }
        
        return;
    }
    
    // ota 数据
    [self otaUpdateValueForCharacteristic:characteristic error:error];
    
}

- (void) peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    
//    if (error != nil) {
//        DebugNSLog(@"write error: %@", [error debugDescription]);
//    }
//
    // 设置录音后再获取当前音量
    if (error == nil && [characteristic.UUID isEqual:_characteristicReadWrite.UUID]) {
        [_servicePeripheral readValueForCharacteristic:_characteristicReadWrite];
        return;
    }
    
    if ([characteristic.UUID isEqual:CABLeService.SPOTA_MEM_DEV_CBUUID]
        || [characteristic.UUID isEqual:CABLeService.SPOTA_GPIO_MAP_CBUUID]
        || [characteristic.UUID isEqual:CABLeService.SPOTA_PATCH_LEN_CBUUID]
        )
    {
        
        if (!error) {
            DebugNSLog(@"OTA Data written successfully");
            [[NSNotificationCenter defaultCenter] postNotificationName:CAGenericServiceManagerDidSendValue object:characteristic];
        } else {
            DebugNSLog(@"OTA Failed to write characteristic %@", characteristic.UUID);
            [[NSNotificationCenter defaultCenter] postNotificationName:CAGenericServiceManagerWriteError object:characteristic];
        }
        
    }
   
    
}

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    if (error == nil) {
        if ([characteristic isNotifying]) {
            [peripheral readValueForCharacteristic:characteristic];
        } else {
            DebugNSLog(@"characteristic :%@", characteristic);
        }
    } else {
        DebugNSLog(@"%d %s uuid:%@ error:%@ ", __LINE__, __func__, characteristic.UUID.UUIDString, error);
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
    
}

-(void)sendValue:(CBPeripheral *)peripheral sendData:(NSData *)data type:(CBCharacteristicWriteType)type
{

}

-(CAPacket *)packetObj
{
    if (!_packetObj) {
        _packetObj = [[CAPacket alloc] init];
    }
    return _packetObj;
}

/** ota 相关 **/
+ (CBUUID*) SPOTA_SERVICE_CBUUID {
    return SPOTA_SERVICE_CBUUID;
}

+ (CBUUID*) SPOTA_MEM_DEV_CBUUID {
    return SPOTA_MEM_DEV_CBUUID;
}

+ (CBUUID*) SPOTA_GPIO_MAP_CBUUID {
    return SPOTA_GPIO_MAP_CBUUID;
}

+ (CBUUID*) SPOTA_MEM_INFO_CBUUID {
    return SPOTA_MEM_INFO_CBUUID;
}

+ (CBUUID*) SPOTA_PATCH_LEN_CBUUID {
    return SPOTA_PATCH_LEN_CBUUID;
}

+ (CBUUID*) SPOTA_PATCH_DATA_CBUUID {
    return SPOTA_PATCH_DATA_CBUUID;
}

+ (CBUUID*) SPOTA_SERV_STATUS_CBUUID {
    return SPOTA_SERV_STATUS_CBUUID;
}

+ (CBUUID*) SUOTA_VERSION_CBUUID {
    return SUOTA_VERSION_CBUUID;
}

+ (CBUUID*) SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID {
    return SUOTA_PATCH_DATA_CHAR_SIZE_CBUUID;
}

+ (CBUUID*) SUOTA_MTU_CBUUID {
    return SUOTA_MTU_CBUUID;
}

+ (CBUUID*) SUOTA_L2CAP_PSM_CBUUID {
    return SUOTA_L2CAP_PSM_CBUUID;
}

@end
